﻿/*
    * Designer:       Virgil  
    * Description:    The code logic of the application
    * Created:         06/07/2010
    * History:
==============================================================
    * Author      DateTime        Alter Description
==============================================================
    */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Reflection;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Win32;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace SudokuWPF
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        ObservableCollection<ISudokuSolver> Solvers = new ObservableCollection<ISudokuSolver>();//用于存放解题器
        AppDomain SolverDomain = null;//应用程序域，应用程序在其中执行的独立环境
        BackgroundWorker solverWorker;//在单独的线程上执行操作
        //窗口加载
        void WindowLoaded(object sender,RoutedEventArgs e)
        {
            TitleReflect.Fill = new VisualBrush(TitleText); //标题文字的渲染

            string[] plugins = Directory.GetFiles("Solvers\\", "*.dll");//加载程序集搜索的应用程序基子目录
            foreach (string p in plugins)
            {
                LoadSolvers(p); //加载解题器
            }

            SolverList.ItemsSource = Solvers;   //加载解题器到菜单

            TimerControls.IsEnabled = false;    //默认状态计时器不可用
            TimerControls.Opacity = 0.25;       //计时器偏暗

            Graph.SelectionChanged += new SelectionChangedEventHandler(this.PluginListSelectionChanged);                    //当解题器插件的选项改变时
            //按钮的初始状态
            BenchButton.IsEnabled = false;
            SolverGenRadio.IsEnabled = false;
            FastGenRadio.IsChecked = true;
            SolverGenRadio.IsChecked = false;
            SolveButton.IsEnabled = false;
        }
        void LoadSolvers(string path)
        {
            if (SolverDomain == null)
            {
                AppDomainSetup ads = new AppDomainSetup();//ads获取创建该对象时传递至域的安装信息
                ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;//获取包含该应用程序的基目录
                ads.PrivateBinPath = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(path));//获取应用程序基目录下的目录列表
                PermissionSet ps = new PermissionSet(null);//初始一个权限的集合ps
                ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));//添加唯一的权限执行
                SolverDomain = AppDomain.CreateDomain("New AD", null, ads, ps); //创建新的域，存放在我们的新领域对它的引用
            }

            FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
            byte[] assemblyData = new byte[stream.Length];
            stream.Read(assemblyData, 0, (int)stream.Length);//从流中读取字节块并将该数据写入给定缓冲区中assemblyData

            Assembly asm = SolverDomain.Load(assemblyData);//建立一个程序集，并加载

            Type[] ts = asm.GetTypes();//获取asm的Type对象并赋给ts
            foreach (Type t in ts)
            {
                if (Array.IndexOf(t.GetInterfaces(), typeof(ISudokuSolver)) != -1)//获取到接口
                {
                    Type containter = typeof(SudokuSolverContainer);
                    SudokuSolverContainer ssc = SolverDomain.CreateInstanceAndUnwrap(containter.Assembly.FullName, containter.FullName) as SudokuSolverContainer;//创建SudokuSolverContainer的新实例
                    ssc.Init(t);
                    Solvers.Add(ssc);//添加
                }
            }
        }
        //解题插件菜单选项改变的事件
        public void PluginListSelectionChanged(object sender, RoutedEventArgs e)
        {
            //当解题器插件菜单中的选项为空时
            if (SolverList.SelectedItem == null)
            {
                BenchButton.IsEnabled = false;
                SolverGenRadio.IsEnabled = false;
                FastGenRadio.IsChecked = true;
                SolverGenRadio.IsChecked = false;
                SolveButton.IsEnabled = false;
            }
            else//有解题器被选中，按钮可用
            {
                BenchButton.IsEnabled = true;
                SolverGenRadio.IsEnabled = true;
                SolveButton.IsEnabled = true;
            }
            if (Graph.SelectedItem == null) return;
            if (sender == Graph)
            {
                SolverList.SelectedItem = ((SolverResult)Graph.SelectedItem).Solver;
            }
            else if (sender == SolverList)
            {
                if (((SolverResult)Graph.SelectedItem).Solver != SolverList.SelectedItem)
                {
                    foreach (SolverResult s in Graph.Items)
                    {
                        if (s.Solver == SolverList.SelectedItem)
                        {
                            Graph.SelectedItem = s;
                            return;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 加载程序集
        /// </summary>
        /// <param name="path">路径</param>
        #region 计时器
        //计时器的点击后时间暂停
        void PauseTimer(object sender, RoutedEventArgs e)
        {
            Storyboard s = this.Resources["TimerAnimation"] as Storyboard;
            s.Pause(this);
            Board.IsEnabled = false;//面板禁用
        }
        //计时器的点击后时间恢复
        void ResumeTimer(object sender, RoutedEventArgs e)
        {
            Storyboard s = this.Resources["TimerAnimation"] as Storyboard;
            s.Resume(this);
            Board.IsEnabled = true;
        }
        //计时器时间时间-包括全部填写正确和时间用完
        void TimerDone(object sender, EventArgs e)
        {
            TimerControls.Opacity = 0.25;
            TimerControls.IsEnabled = false;
            StopWatchControl.IsChecked = false;
            if (Board.GameBoard.IsFull && Board.GameBoard.IsValid)
            {
                MessageBox.Show("你赢了!");
            }
            else
            {
                MessageBox.Show("你的时间用完了! 祝你下次好运.");
            }
        }
        #endregion
        #region 按钮的处理
        
        private void NewGame_Click(object sender, RoutedEventArgs e)
        {
            Board.GameBoard = new Board((int)BoardSize.SelectedItem); //游戏的规格
            Storyboard s = this.Resources["TimerAnimation"] as Storyboard;

            if (FastGenRadio.IsChecked == true) //快速生成
            {
                Board.GameBoard.GenerateGame((int)BoardSize.SelectedItem * 2);
                Board.GameBoard.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(GameBoard_PropertyChanged);
            }
            else// 带解题器的生产，速度较慢
            {
                Board b = Board.GameBoard;
                int givens = (int)BoardSize.SelectedItem * 2;   //生成的游戏的已知数个数
                ISudokuSolver sol = SolverList.SelectedItem as ISudokuSolver;
                solverWorker = new BackgroundWorker();  //初始化
                ShowWait(); // 生产题目时的请等待消息，有好设计
                solverWorker.DoWork += new DoWorkEventHandler(delegate(object dwsender, DoWorkEventArgs dwe)//DoWorkEventHandler 委托 
                {
                    b.GenerateGameUsingSolver(sol, givens); //调用使用解题器的生成游戏方法
                });
                solverWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object rwcsender, RunWorkerCompletedEventArgs rwce)//当后台操作已完成、被取消或引发异常时
                {
                    MessageLayer.IsEnabled = false;
                    if (NoTimerRadio.IsChecked == false)
                    {
                        s.Begin(this, true);
                    }
                    Board.GameBoard.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(GameBoard_PropertyChanged);//监视棋盘是否填满
                });
                solverWorker.RunWorkerAsync();//后台工作
            }

            s.Stop(this);
            //没计时器
            if (NoTimerRadio.IsChecked == true)
            {
                MinNumber.Tag = 59;
                SecNumber.Tag = 59;
                SubSecNumber.Tag = 59;
                TimerControls.Opacity = 0.25;
                TimerControls.IsEnabled = false;
                StopWatchControl.IsChecked = false;
            }
            else
            {
                Int32 length;
                if (EasyTimerRadio.IsChecked == true)
                {
                    length = 15;
                }
                else if (MediumTimerRadio.IsChecked == true)
                {
                    length = 10;
                }
                else
                {
                    length = 5;
                }
                //s.CutoffTime = TimeSpan.FromMinutes(length);
                s.Children[0].Duration = new Duration(TimeSpan.FromMinutes(length));
                s.Children[1].Duration = new Duration(TimeSpan.FromMinutes(length));
                s.Children[2].RepeatBehavior = new RepeatBehavior(TimeSpan.FromMinutes(length));
                s.Children[3].RepeatBehavior = new RepeatBehavior(TimeSpan.FromMinutes(length));
                ((Int32Animation)s.Children[1]).From = length - 1;
                StopWatchControl.IsChecked = true;
                MinNumber.Tag = length - 1;
                TimerControls.Opacity = 1;
                TimerControls.IsEnabled = true;
                if (FastGenRadio.IsChecked == true)
                    s.Begin(this, true);
            }
            BenchButton.IsEnabled = true;
            SolverGenRadio.IsEnabled = true;
            SolveButton.IsEnabled = true;
            Board.IsEnabled = true;
        }

        private void SaveGame_Click(object sender, RoutedEventArgs e)
        {
            if (TimerControls.IsEnabled)
            {
                MessageBox.Show("计时器的时间将不被保存!");
            }
            SaveFileDialog sfd = new SaveFileDialog();//弹出对话框
            //设置对话框的属性
            sfd.InitialDirectory = System.Windows.Forms.Application.StartupPath ;
            sfd.OverwritePrompt = true;
            sfd.Filter = "数独保存文件 (*.sudoku)|*.sudoku";
            sfd.Title = "选择一个文件来保存";
            sfd.ValidateNames = true;
            sfd.FileName = "数独游戏记录.sudoku";
            if (sfd.ShowDialog(this) == true)
            {
                Stream s = new FileStream(sfd.SafeFileName, FileMode.Create);
                IFormatter f = new BinaryFormatter();   //以二进制格式将对象序列化
                f.Serialize(s, Board.GameBoard.ToArray()); //将对象 棋盘对象序列化为所提供的流s
                s.Close();
            }
        }

        private void LoadGame_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory = System.Windows.Forms.Application.StartupPath;
            ofd.Filter = "数独保存文件  (*.sudoku)|*.sudoku";
            ofd.Title = "打开";
            ofd.ValidateNames = true;
            ofd.FileName = "数独游戏记录.sudoku";

            if (ofd.ShowDialog(this) == true)
            {
                Stream s = null;
                try
                {

                    s = new FileStream(ofd.SafeFileName, FileMode.Open);
                }
                catch (IOException)
                {
                    MessageBox.Show("你所选择的文件无法被打开");
                    return;
                }

                IFormatter f = new BinaryFormatter();
                int?[,] a = f.Deserialize(s) as int?[,];    //反序列化所提供流中的数据到数组
                Board.GameBoard = new Board(a.GetLength(0));//将信息设置到棋盘
                Board.GameBoard.FromArray(a);               //获取谜题信息
                Storyboard sb = this.Resources["TimerAnimation"] as Storyboard;
                sb.Stop(this);
                MinNumber.Tag = 59;
                SecNumber.Tag = 59;
                SubSecNumber.Tag = 59;
                TimerControls.IsEnabled = true;
                StopWatchControl.IsChecked = false;
                TimerControls.Opacity = 1;
                if (SolverList.SelectedItem != null)
                {
                    BenchButton.IsEnabled = true;
                    SolverGenRadio.IsEnabled = true;
                    SolveButton.IsEnabled = true;
                }
                s.Close();
                Board.IsEnabled = true;
            }
        }
  
        private void Quit_Click(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show("你确定要退出游戏?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                Application.Current.Shutdown();
            }
        }

        private void SolveButton_Click(object sender, RoutedEventArgs e)
        {
            ISudokuSolver sol = SolverList.SelectedItem as ISudokuSolver;
            Board.IsEnabled = true;
            if (sol == null)
            {
                ShowMessage("没有解题器!");
            }
            else
            {
                Storyboard sb = this.Resources["TimerAnimation"] as Storyboard;
                sb.Stop(this);
                MinNumber.Tag = 59;
                SecNumber.Tag = 59;
                SubSecNumber.Tag = 59;
                TimerControls.Opacity = 0.25;
                TimerControls.IsEnabled = false;
                StopWatchControl.IsChecked = false;
                ShowWait();

                int?[,] a = Board.GameBoard.ToArray();
                bool solved = false;

                solverWorker = new BackgroundWorker();

                solverWorker.DoWork += new DoWorkEventHandler(delegate(object dwsender, DoWorkEventArgs dwe)
                {
                    solved = sol.Solve(ref a);
                });
                solverWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object rwcsender, RunWorkerCompletedEventArgs rwce)
                {
                    MessageLayer.IsEnabled = false;
                    if (!solved)
                    {
                        MessageExpander.Header = "消息";
                        ShowMessage("没有答案!");
                    }
                    else
                    {
                        Board.GameBoard.FromArray(a);
                    }
                });
                solverWorker.RunWorkerAsync();
            }
        }

        //棋盘填满和验证的处理
        void GameBoard_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsFull")
            {
                if (Board.GameBoard.IsFull && Board.GameBoard.IsValid)
                {
                    this.TimerDone(null, null);
                }
            }
        }

        private void BenchButton_Click(object sender, RoutedEventArgs e)
        {
            SolverResult s = new SolverResult();    //存储游戏结果
            s.Solver = SolverList.SelectedItem as ISudokuSolver;    //解题器为列表中所选
            int?[,] arr = Board.GameBoard.ToArray();                //将迷局存储到数组
            BenchButton.IsEnabled = false;                          //按钮禁用
            InfoPanel.Visibility = Visibility.Hidden;
            WaitPanel.Visibility = Visibility.Visible;
            long tick = DateTime.Now.Ticks;

            solverWorker = new BackgroundWorker();      //在单独的线程上执行操作

            solverWorker.DoWork += new DoWorkEventHandler(delegate(object dwsender, DoWorkEventArgs dwe)
            {
                s.Failed = !s.Solver.Solve(ref arr);            //调用解题器解题
                s.TimeTaken = TimeSpan.FromTicks((DateTime.Now.Ticks - tick));  //计算时间
            });
            solverWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object rwcsender, RunWorkerCompletedEventArgs rwce)           //计算出来后
            {
                Graph.Items.Add(s);         //将答案以图像显示
                InfoPanel.Visibility = Visibility.Visible;
                WaitPanel.Visibility = Visibility.Hidden;
                BenchButton.IsEnabled = true;
            });
            solverWorker.RunWorkerAsync();
        }

        void ClearGraph_Click(object sender, RoutedEventArgs e)
        {
            Graph.Items.Clear();
        }

        private void Help_Click(object sender, RoutedEventArgs e)
        {
            SudokuWPF.Help.MainHelp window= new SudokuWPF.Help.MainHelp();
            window.Show();
        }

        private void About_Click(object sender, RoutedEventArgs e)
        {
            MessageExpander.Header = "关于我们";
            string product = "产品名称：数独（Sudoku）";
            string version = "版本：V1.0";
            string copyright = "版权：Copyright © Steven Cai 2009";
            string Email = "如有发现bug，欢迎反馈 Email：675895105@qq.com";
            string unit = "班级：06计算机科学与技术2班";
            string description = "说明：小蔡(蔡春生)的毕业之作，一款经典益智类游戏，主要使用WPF开发。";
            ShowMessage(string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}", product, version, copyright, unit, description ,Email));
        }
        #endregion 

        #region 消息框
        private void ShowMessage(string m)
        {
            MessageText.Text = m;
            MessageExpander.Visibility = Visibility.Visible;
            WaitExpander.Visibility = Visibility.Hidden;
            MessageLayer.IsEnabled = true;
        }

        private void ShowWait()
        {
            MessageExpander.Visibility = Visibility.Hidden;
            WaitExpander.Visibility = Visibility.Visible;
            MessageLayer.IsEnabled = true;
        }

        void MessageClosed(object sender, RoutedEventArgs e)
        {
            MessageLayer.IsEnabled = false;
        }
        #endregion

        private void CreateGame_Click(object sender, RoutedEventArgs e)
        {

            if (CreateGame.Content.ToString() == "手动创建游戏")
            {
                Board.GameBoard = new Board((int)BoardSize.SelectedItem); //游戏的规格
                Board.GameBoard.CreateGame();
                NewGame.IsEnabled = false;
                SaveGame.IsEnabled = false;
                LoadGame.IsEnabled = false;
                Storyboard sb = this.Resources["TimerAnimation"] as Storyboard;
                sb.Stop(this);
                MinNumber.Tag = 59;
                SecNumber.Tag = 59;
                SubSecNumber.Tag = 59;
                TimerControls.IsEnabled = true;
                StopWatchControl.IsChecked = false;
                Board.IsEnabled = true;
                CreateGame.Content = "完成输入";
            }
            else
            {
                Board.GameBoard.CreateGameOver();
                MessageBox.Show("输入完毕，可以开始游戏或选择解题器进行验证是否有解");
                NewGame.IsEnabled = true;
                LoadGame.IsEnabled = true;
                SaveGame.IsEnabled = true;
                MyControl.IsEnabled = true;
                TimerControls.Opacity = 1;
                SolveButton.IsEnabled = true;
                CreateGame.Content = "手动创建游戏";
            }
            
        }
    }
}
